package com.zhangxin.aiInterview.manager.redis.rate_limiter;

import org.springframework.core.io.ClassPathResource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
import java.util.stream.Collectors;

/**
 * Redis限流管理器
 * 使用滑动窗口限流算法，基于Redis List实现
 */
@Component
public class RateLimitManager {

    @Resource
    private StringRedisTemplate stringRedisTemplate;
    
    private String luaScript;

    /**
     * 执行时机：构造函数执行完毕并且所有依赖都成功注入
     */
    @PostConstruct
    public void init() {
        try {
            ClassPathResource resource = new ClassPathResource("rate_limiting.lua");
            try (BufferedReader reader = new BufferedReader(
                    new InputStreamReader(resource.getInputStream(), StandardCharsets.UTF_8))) {
                luaScript = reader.lines().collect(Collectors.joining("\n"));
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to load rate limiting Lua script", e);
        }
    }

    /**
     * 检查是否允许请求通过
     * @param key 限流key
     * @param limit 限制次数
     * @param window 时间窗口（秒）
     * @return true允许通过，false触发限流
     */
    public boolean isAllowed(String key, int limit, int window) {
        try {
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(luaScript, Long.class);
            long now = System.currentTimeMillis();
            Long result = stringRedisTemplate.execute(
                redisScript,
                Collections.singletonList(key),
                String.valueOf(limit),
                String.valueOf(window * 1000), // 转换为毫秒
                String.valueOf(now)
            );
            return result != null && result == 1;
        } catch (Exception e) {
            // 如果Redis异常，允许通过（降级处理）
            return true;
        }
    }

    /**
     * 获取客户端IP地址并进行格式化处理
     * @param request HttpServletRequest
     * @return 处理后的IP地址（IPv6地址转换为IPv4兼容格式，并替换冒号）
     */
    public String getClientIpAddress(javax.servlet.http.HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return formatIpForRedis(xForwardedFor.split(",")[0].trim());
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty()) {
            return formatIpForRedis(xRealIp);
        }
        
        String proxyClientIp = request.getHeader("Proxy-Client-IP");
        if (proxyClientIp != null && !proxyClientIp.isEmpty()) {
            return formatIpForRedis(proxyClientIp);
        }
        
        String wlProxyClientIp = request.getHeader("WL-Proxy-Client-IP");
        if (wlProxyClientIp != null && !wlProxyClientIp.isEmpty()) {
            return formatIpForRedis(wlProxyClientIp);
        }
        
        return formatIpForRedis(request.getRemoteAddr());
    }

    /**
     * 格式化IP地址，使其适合作为Redis key
     * 1. IPv6地址转换为压缩格式
     * 2. 替换冒号为下划线，避免Redis层级解析
     * @param ip 原始IP地址
     * @return 格式化后的IP地址
     */
    private String formatIpForRedis(String ip) {
        if (ip == null || ip.isEmpty()) {
            return "unknown";
        }
        
        // 处理IPv6本地回环地址
        if ("0:0:0:0:0:0:0:1".equals(ip) || "::1".equals(ip)) {
            return "127_0_0_1";
        }
        
        // 处理IPv6映射的IPv4地址
        if (ip.startsWith("0:0:0:0:0:0:0:0:0:0:0:0:0:0:0:1") || ip.startsWith("::ffff:127.0.0.1")) {
            return "127_0_0_1";
        }
        
        // 替换所有冒号为下划线
        return ip.replace(':', '_');
    }
}